<template>
    <div class="formBox">
      <video src="../../assets/video/bg-video.mp4" class="video" muted loop autoplay="true"></video>
      <div  class="demo-loginForm">
        <h1>千峰管理系统</h1>
        <svg class="icon jiaobiao" aria-hidden="true" @click="changeFlag">
              <use :xlink:href=[jiaobiao]></use>
          </svg>
        <el-form :model="loginForm" status-icon :rules="rules" ref="loginForm" label-width="100px">
          <!-- 常规登陆部分 -->
          <div class="commonLogin" v-if="flag && !sms">
             <el-form-item label="用户名" prop="username" class="item">
                <el-input type="text" v-model="loginForm.username" autocomplete="off" class="input"></el-input>
            </el-form-item>
            <el-form-item label="密码" prop="password" class="item" >
                <el-input type="password" v-model="loginForm.password" autocomplete="off" class="input"></el-input>
            </el-form-item>
            <el-form-item label="验证码" prop="captcha" class="item"  >
                <el-input maxlength="5"
						v-model="loginForm.captcha"
						class="captcha" @keyup.enter.native="submitForm('loginForm')"></el-input>
					<span class="captcha-svg"
         v-loading="loading">
						<i  v-html="captchaSvg" @click="updateCaptcha"></i>
					</span>
            </el-form-item>
            <el-form-item class="m">
                <el-button type="primary" @click="submitForm('loginForm')">提交</el-button>               
            </el-form-item>

             <el-form-item class="iPhone">
              <svg class="icon" aria-hidden="true" @click="changeFlag">
                  <use xlink:href="#icon-iphone"></use>
              </svg>
              <a href="javascript:;" @click="sms = true">短信登入</a>                               
            </el-form-item>
          </div>
           
           <!-- 二维码登录部分 -->
           <div class="codeLogin" v-if="!flag && !sms">
              <div class="img" v-loading="codeLoading">
                <img :src="imgUrl" alt="二维码">
                <div class="mask" :style="reqImg" v-show="showMask" @click="getQrCode"></div>
              </div>

                <p>
                  <svg class="icon" aria-hidden="true">
                    <use xlink:href="#icon-weixin" class="weixinIcon"></use>
                  </svg>
                  <span v-text="TipMsg"></span>
                </p>
           </div>

           <!-- 短信验证码登入 -->
			<div class="smsContainer" v-if="sms">
				<el-form-item label="手机号" status-icon="false">
					<el-input maxlength="11"
						v-model="phoneNumber"
						class="captcha phone"
            ></el-input>
					<span class="captcha-svg"
            v-text="smsRetryMsg"
						style="color: #888; line-height: 45px; text-decoration: underline"
            @click="sendSmsCode"
            >
					</span>
				</el-form-item>
				<el-form-item label="验证码">
					<el-input v-model="smsCode" @keyup.native.enter="smsSubmit"></el-input>
				</el-form-item>
				<el-form-item>
					<el-button type="primary" @click="smsSubmit">提交</el-button>
				</el-form-item>
			</div>
        </el-form>

      </div>
    </div>
</template>

<script>
    //引入api的方法
    import * as api from "@/api/user"
    //引入图片
    import successImg from "../../assets/img/scancode.png"
    import failImg from "../../assets/img/invalidQr.png"
    // console.log(successImg)

    //引入socket.io
    import socketIo from "socket.io-client"

    //引入qrcode 生成二维码
    import qr from "qrcode"

    //映射vuex
    import {mapMutations} from "vuex"

    //校验验证码
    var validateCaptcha = (rule, value, callback) => {
      callback()
      };
    //校验用户名
    var validateUsername = (rule, value, callback) => {
      //value代表输入框里的内容
      //callback回调函数 传入参数代表验证失败
        // console.log(value)
        //用户名正则，4到16位（字母，数字，下划线，减号）
        var userNamePattern = /^[a-zA-Z0-9_-]{3,16}$/;
        if(!userNamePattern.test(value)){
          callback("4到16位 字母,数字,下划线,减号")
        }else {
          callback()
        }
      };
    //校验密码
    var validatePassword = (rule, value, callback) => {
         //至少8-16个字符，至少1个大写字母，1个小写字母和1个数字，其他可以是任意字符
      //  var pwdPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/;

       if(value.length < 3){
          callback("请输入正确的密码")
        }else {
          callback()
        }
      
        
      };

  export default {
    name:"login",
    data() {
      return {
        captchaSvg:"",//手机验证码
        loading : true,//过度的动画 
        flag:true,//控制二维码显示还是电脑显示
        phoneNumber:"",//手机号
        smsCode:"",//验证码
        smsRetryMsg: "点击发送验证码", //xx秒之后重新发送提示
        sms:false,//控制短信登入界面
        imgUrl:"",//二维码图片
        showMask:false,//控制二维码遮罩是否显示
        codeLoading:true,//控制二维码一开始显示的过度动画
        TipMsg:"请使用手机微信扫码登入",//扫码的提示信息
        smsDisabled:false,//是否能再次发送验证码
        loginForm: {
          //登入输入框里的数据
          username: '',
          password: '',
          captcha: '',
          
        },
        reqImg:{
          backgroundImage:`url(${failImg})`
        },
        rules: {
          username: [
            { validator: validateUsername, trigger: 'blur' }
          ],
          password: [
            { validator: validatePassword, trigger: 'blur' }
          ],
          captcha: [
            { validator: validateCaptcha, trigger: 'blur' }
          ]
        }
      };
    },
    computed:{
      jiaobiao(){
        return this.flag?"#icon-erweimajiaobiao":"#icon-diannaojiaobiao"
      }
    },
    created(){
      //立即调用获取验证码的方法
      this.updateCaptcha()
    },
    methods: {
      // 映射vuex长得mutation
      ...mapMutations(["SET_USERINFO"]),

      //点击提交验证手机验证码
      async smsSubmit(){
        let smsLoginRes = await api.smsLogin(this.smsCode)
        console.log(smsLoginRes)
        //解构对应的内容
              let {state,userInfo,permission:{buttons},token} = smsLoginRes.data
              //当state为true的时候将userInfo permission token 存入localStorage中
              if(state){
                // localStorage.setItem("login-userInfo",JSON.stringify(userInfo))
                localStorage.setItem("login-permissionBtn",JSON.stringify(buttons))
                localStorage.setItem("login-token",token)
                 //调用vuex的方法 设置用户信息
                  this.SET_USERINFO(userInfo)
                this.$router.push("/")
              }

      },
      //点击发送验证码
      async sendSmsCode(){
        //点击一次让一分钟之内只能发送一次 此时的smsDisabled是true直接就return后面的点击事件就不触发了
        if(this.smsDisabled){
          //提示错误信息
          this.$message.error("一分钟之内只能发送一次")
          return
        }
        // console.log(this.phoneNumber)
        let smsRes = await api.getSmsCode(this.phoneNumber)
        // console.log(smsRes)
        let {state} = smsRes.data
        if(state){
          //当用户收到验证码的时候 就将开关变成true 
          this.smsDisabled = true

          //提示短信发送成功
          this.$message.success("短信发送成功")
          //在实例上添加一个计数器
          this.smsSecond = 60
          //在实例上添加一个定时器 用来短信倒计时
          this.smsInterval = setInterval(()=>{
            this.smsSecond--
            if(this.smsSecond === 0){
              clearInterval(this.smsInterval)
              this.smsRetryMsg = "点击发送验证码"
              //计时器结束的时候也要将开关关掉
              this.smsDisabled = false
              return
            }
            this.smsRetryMsg = `${this.smsSecond}秒后重新发送`
          },1000)
        }
      },
      //控制页面显示
      changeFlag(){
        // console.log(1)
        this.flag = !this.flag
        // console.log(this.flag)
        this.sms = false
      },
      //提交验证表单
      //常规登入
      async submitForm(formName) {
        //formName是表单的ref名字
        // console.log(this.$refs)
         //登入逻辑
        //1.先要进行本地的表单校验
         //2.表单校验通过之后 通过v-model获取输入的username 和 password
        //3.校验验证码
        //4.校验通过后 发起请求  请求登入接口  传入用户名和密码
        //5.跳转到主页,显示主页

        //这个validate是组件的方法 valid返回的是布尔值
        //这个一定要写成箭头函数 否则有指向问题
        this.$refs[formName].validate(valid=>{
          console.log(valid)
          if(valid){
            //本地校验通过

            //加载动画
             const loading = this.$loading({
                lock: true,
                text: 'Loading',
                spinner: 'el-icon-loading',
                background: 'rgba(0, 0, 0, 0.7)'
            });
            let {username,password,captcha} = this.loginForm
            //校验验证码
            api.verifyCaptcha(captcha)
            .then(async (res)=>{
              // console.log(res)
              let {state} = res.data
              if(state){
                //验证正确

                //验证用户名用户密码是否能登入
                let loginRes = await api.login(username,password)
                let {state:loginState , msg ,token ,userInfo} = loginRes.data
                if(loginState){
                  //登入成功 关闭加载动画
                  loading.close()
                  //将token存入localStorage中
                  localStorage.setItem("login-token",token)
                  //调用vuex的方法 设置用户信息
                  this.SET_USERINFO(userInfo)
                  // console.log("登入成功")
                  this.$router.push("/")

                  // 提示登入成功
                  this.$message({
                    message:msg,
                    type:"success",
                    duration:1000
                  })
                }else{
                  //登入失败 关闭动画
                  loading.close()

                }
              }else {
                 //验证码失败 关闭动画
                  loading.close()
                  //验证码失败 刷新验证码
                  this.updateCaptcha()
              }
            })
          }else{
            //本地校验不通过
          }

        })

       
        
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      },
      //封装获取验证码的函数
      updateCaptcha(){
        this.loading = true //请求之前有动画
        api.getCaptcha().then(res=>{
          // console.log(res)
          let {img} = res.data//解构验证码
          this.captchaSvg = img
          this.loading = false //请求成功之后没有动画

        })
      },
      //获得二维码
      async getQrCode(sid){
        //先关掉遮罩
        this.showMask = false
        //打开加载二维码动画
        this.codeLoading = true

        sid = localStorage.getItem("code-sid") ?? sid

         //调用接口获取二维码url
            let qrResult = await api.getQrcode(sid)
            // console.log(qrResult)  
            //解构 scanCodeUrl 和 state 
            let {scanCodeUrl,state:qrState} = qrResult.data
            //scanCodeUrl是一个地址可以用qr转换成二维码图片
            //判断请求状态
            if(qrState){
              //如果请求成功
              //使用qr插件转换
              //传入两个参数 第一个是需要转换的路径  第二个是一个回调函数 第一个参数是错误信息 第二个是成功的回调
              qr.toDataURL(scanCodeUrl,(err,imgUrl)=>{
                if(err){
                  //出错的情况下
                  //注意箭头函数 否则指向有问题
                  return this.$messageBox.error(err)
                }
                // console.log(imgUrl)
                this.imgUrl = imgUrl
                //在二维码加载好之后关闭动画过渡
                this.codeLoading = false
              })

            }
      }
      

    },
    watch: {
      //界面切换
      flag(newFlag){
        // console.log(newFlag)
        if(!newFlag){
          //代表切换到二维码视角

          //进入到二维码视角就立刻打开 二维码加载动画
          this.codeLoading = true

          this.TipMsg = "请使用手机微信扫码登入"

          //每次切换过来的时候都需要把遮罩关闭
          this.showMask = false

          //建立socket链接
          //因为是https协议所以是wss
          let io = socketIo("wss://chst.vip")

          //扫码成功的时候
          io.on("scancodeSuccess",async (data)=>{
            //扫码成功的时候显示成功扫码的遮罩
            this.showMask = true
            this.reqImg.backgroundImage = `url(${successImg})`
            this.TipMsg = "扫码成功"
            // console.log(data)
            //成功之后返回数据 解构
            let {state:codeState,wechatCode} = data
            // console.log("wechatCode",wechatCode)
            if(codeState){
              //扫码成功
              let scancodeRes = await api.wechatLogin(wechatCode);
              // console.log(scancodeRes)
              //解构对应的内容
              let {state,userInfo,permission:{buttons},token} = scancodeRes.data
              //当state为true的时候将userInfo permission token 存入localStorage中
              if(state){
                // localStorage.setItem("login-userInfo",JSON.stringify(userInfo))
                localStorage.setItem("login-permissionBtn",JSON.stringify(buttons))
                localStorage.setItem("login-token",token)
                 //调用vuex的方法 设置用户信息
                  this.SET_USERINFO(userInfo)
                this.$router.push("/").catch(()=>{
        alert("请先登录")
      })
              }
             
            }

          })

          //二维码失效的时候
          io.on("invalidCode",data=>{
            // console.log(data)
            let {state} = data
            if(!state){
              this.showMask = true
              this.TipMsg = "二维码已失效"
            }
          })

          io.on("connectSuccess",async (data)=>{
            //解构出sid
            let {sid} = data
            // console.log(sid)

            // 存入本地
            localStorage.setItem("code-sid",sid)
            this.getQrCode(sid)
           
          })
        }
      },
      //短信登录
      sms(newVal){
        //不在短信登录的页面的时候
        if(!newVal){
          //清除定时器
          if(this.smsInterval){
            clearInterval(this.smsInterval)

          }
          //重置信息
          this.smsRetryMsg = "点击发送验证码"
        }

      }
    }
  }
</script>

<style lang="less" scoped>
//样式设置不上的情况,解决方案
//1.检查类名是否正确
//2.检查权重是否正确
//3.检查是否需要穿透
.video {
    position: fixed;
		left: 0;
		top: 0;
		right: 0;
		bottom: 0;
}


//最大盒子
.demo-loginForm {
  width: 400px;
  height: 550px;
  display: flex;
  flex-direction: column;
  position: absolute;
  bottom: 8%;
  right: 10%;
  align-items: center;
  // justify-content: center;
  background-color: rgba(0,0,0,.3);
}

//标题
h1 {
  color: #fff;
  font-size: 32px;
  margin:80px 0 60px;
}


//角标部分
.jiaobiao {
    position: absolute;
    top: 0;
    right: 0;
    color: #fff;
    font-size: 50px;
    cursor:pointer;
  }

//常规登录部分

.el-form {
  width: 400px;
  display: flex;
  flex-direction: column;
  align-items: center;


}


/deep/.el-form-item__content{
  text-align: center !important;
}



.input {
  width: 250px;
  height: 40px;
  padding: 0 10px;
}

/deep/ .el-form-item__label {
 color: #fff;
}

/deep/ .el-button--primary{
  width: 250px;
  height: 40px;
}


.captcha-svg {
			background: #fff;
			display: inline-block;
			height: 45px;
			width: 150px;
			text-align: center;
			cursor: pointer;
			border: 0;
			border-radius: 0px 5px 5px 0;
		}

  /deep/ .captcha {
			width: 100px;
			vertical-align: top;

			.el-input__inner {
				width: 100%;
				height: 45px;
				border-radius: 5px 0 0 5px;
				border: 0;
				font-size: 18px;
			}
		}

    //二维码部分
    .codeLogin {
      // background-color: pink;
      width: 100%;
      height: 300px;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      color: #fff;
    }

    .codeLogin .img {
      width: 200px;
      height: 200px;
      position: relative;
    }

     .codeLogin .img img {
      width: 200px;
      height: 200px;
    }

    .codeLogin .img .mask{
      width: 200px;
      height: 200px;
      position: absolute;
      top: 0;
      left: 0;
      background-color: rgba(249, 251, 250, 0.49);
    }

   /deep/ .weixinIcon {
    font-size: 25px !important;
   }

   .m {
    margin-left: -100px;
   }

//短信登入
  .iPhone {
    margin-left: -100px;
  }
  .iPhone a {
    color: #fff;
  }

  .smsContainer {
	padding-right: 20px !important;
	width: 89%;

	/deep/ .el-form-item__label {
		// margin-left: 80px !important
		padding: 0 !important;
		padding-right: 10px !important;
	}

	/deep/ .phone {
		width: 140px !important;
	}

	/deep/ .captcha-svg {
		width: 115px !important;
	}

	/deep/ .el-form-item__content {
		margin: 0;
	}
}
  /deep/ .phone {
		width: 140px !important;
	}

  .captcha-svg {
			background: #fff;
			display: inline-block;
			height: 45px;
			width: 150px;
			text-align: center;
			cursor: pointer;
			border: 0;
			border-radius: 0px 5px 5px 0;
		}

   

  

</style>>
